#pragma once
#include <iostream>
#include <vector>
#include <semaphore>

#include "LockCuard.hpp"

static const size_t defaultSize = 5;

template<class T>
class RingQueue
{
public:
    RingQueue(size_t size = defaultSize)
    :_ringqueue(size), _size(size), _c_step(0), _p_step(0)
    {
        //初始化信号量和锁
        sem_init(&_data_sem, 0, 0);
        sem_init(&_space_sem, 0, size);
        pthread_mutex_init(&_c_mutex, nullptr);
        pthread_mutex_init(&_p_mutex, nullptr);
    }
    //生产者生产
    void Push(const T& in)
    {
        P(_space_sem);
        {
            LockGuard(&_p_mutex);
            _ringqueue[_p_step++] = in;
            _p_step %= _size;
        }
        V(_data_sem);
    }
    //消费者消费
    void Pop(T* out)
    {
        P(_data_sem);
        {
            LockGuard(&_c_mutex);
            *out = _ringqueue[_c_step++];
            _c_step %= _size;
        }
        V(_space_sem);
    }
private:
    //信号量--
    void P(sem_t& sem) {sem_wait(&sem);}
    //信号量++
    void V(sem_t& sem) {sem_post(&sem);}
private:
    std::vector<T> _ringqueue;   //环形队列
    size_t _size;                //队列容量
    size_t _c_step;              //消费者所在位置
    size_t _p_step;              //生产者所在位置
    sem_t _space_sem;
    sem_t _data_sem;
    pthread_mutex_t _c_mutex;
    pthread_mutex_t _p_mutex;
};